//
//  PhotoBrowser.swift
//  PhotoBrowser
//
//  Created by meng on 16/5/17.
//  Copyright © 2016年 leotao. All rights reserved.
//

import UIKit
import Kingfisher

let PADDING:Float = 10.0
class PhotoBrowser: UIViewController {
    weak var delegate: PhotoBrowserDelegate?
    var pagingScrollView: UIScrollView!
    var visiblePages = Set<DisplayView>();
    var recyclePage = Set<DisplayView>();
    var currentPage: Int = 0;
    var rotating = false;
    var viewIsActive = false;
    var previousBounds = CGRectZero;
    var isPerformLayout = false;
    
    // 旋转的时候scrollView的contentOffset会变化。所以需要记录旋转之前的当前页在旋转时重新赋值
    var indexBeforeRotate:Int = 0;
    
    // 存储导航栏的属性
    var _previousNavBarBarTintColor: UIColor?
    var _previousNavBarTintColor: UIColor?
    var _previousNavBarTranslucent: Bool = false;
    var _previousNavBarHidden: Bool = false;
    var _previousBarStyle: UIBarStyle = .Default;
    var _previousBarShadowImage: UIImage?
    var _previousNavigationBarBackgroundImageDefault: UIImage?
    var _previousNavigationBarBackgroundImageCompact: UIImage?
    var savePreviousNavBarStyle = false;
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    init(delegate: PhotoBrowserDelegate?) {
        super.init(nibName: nil, bundle: nil);
        self.delegate = delegate;
        
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PhotoBrowser.imageDidDownload(_:)), name: ImageDownloadCompleteNotification, object: nil);
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        initialize();
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated);
        
        viewIsActive = true;
    }
    
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated);
        
        viewIsActive = false;
    }
    
    func initialize() {
        pagingScrollView = UIScrollView()
        pagingScrollView.frame = pagingScrollViewFrame();
        pagingScrollView.delegate = self;
        pagingScrollView.contentSize = pagingScrollViewContentSize();
        pagingScrollView.pagingEnabled = true;
        self.view.addSubview(pagingScrollView);
        self.view.backgroundColor = UIColor.blackColor();
        self.automaticallyAdjustsScrollViewInsets = false;
        
        reloadData();
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated);
        
        storeNavBarAppearance();
        setNavBarAppearance();
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated);
        
        restoreNavBarAppearance();
    }
    
    func storeNavBarAppearance() {
        savePreviousNavBarStyle = true;
        _previousNavBarBarTintColor = self.navigationController!.navigationBar.barTintColor;
        _previousNavBarTranslucent = self.navigationController!.navigationBar.translucent;
        _previousNavBarTintColor = self.navigationController!.navigationBar.tintColor;
        _previousNavBarHidden = self.navigationController!.navigationBarHidden;
        _previousBarStyle = self.navigationController!.navigationBar.barStyle;
        _previousNavigationBarBackgroundImageDefault = self.navigationController?.navigationBar.backgroundImageForBarMetrics(.Default);
        _previousBarShadowImage = self.navigationController?.navigationBar.shadowImage;
        _previousNavigationBarBackgroundImageCompact = self.navigationController?.navigationBar.backgroundImageForBarMetrics(.CompactPrompt)
    }
    
    func restoreNavBarAppearance() {
        if savePreviousNavBarStyle {
            let navBar = self.navigationController?.navigationBar;
            navBar?.tintColor = _previousNavBarTintColor;
            navBar?.barTintColor = _previousNavBarBarTintColor;
            navBar?.shadowImage = _previousBarShadowImage;
            navBar?.translucent = _previousNavBarTranslucent;
            navBar?.barStyle = _previousBarStyle;
            navBar?.setBackgroundImage(_previousNavigationBarBackgroundImageDefault, forBarMetrics: .Default);
            navBar?.setBackgroundImage(_previousNavigationBarBackgroundImageCompact, forBarMetrics: .CompactPrompt);
        }
    }
    
    func setNavBarAppearance() {
        let navBar = self.navigationController?.navigationBar;
        navBar?.tintColor = UIColor.whiteColor();
        navBar?.barTintColor = nil;
        navBar?.shadowImage = nil;
        navBar?.translucent = true;
        navBar?.barStyle = .BlackTranslucent;
        navBar?.setBackgroundImage(nil, forBarMetrics: .Default);
        navBar?.setBackgroundImage(nil, forBarMetrics: .CompactPrompt);
    }
    
    func setCurrentPhotoIndex(index:Int) {
        if  numOfPhotos() == 0 {
            currentPage = 0;
        } else {
            if  index >= numOfPhotos() {
                currentPage = numOfPhotos() - 1;
            } else {
                currentPage = index;
            }
        }
        
        if self.isViewLoaded() {    //  如果view已经加载了则去更新界面
            self.scrollToPageAtIndex(currentPage, animated: false);
            if !viewIsActive {
                self.tilePage();
            }
        }
    }
    
    func reloadData() {
        let numOfPhotos = self.numOfPhotos();
        if numOfPhotos > 0 {
            currentPage = max(0, min(currentPage, numOfPhotos));
        } else {
            currentPage = 0;
        }
        
        if self.isViewLoaded() {
            while pagingScrollView.subviews.count > 0 {
                pagingScrollView.subviews.last?.removeFromSuperview();
            }
            
            performLayout();
            self.view.setNeedsLayout();
        }
    }
    
    func performLayout() {
        isPerformLayout = true;
        
        visiblePages.removeAll();
        recyclePage.removeAll();
        pagingScrollView.contentOffset = contentoffsetForPage(currentPage);
        tilePage();
        isPerformLayout = false;
    }

    func scrollToPageAtIndex(index:Int, animated:Bool) {
        pagingScrollView.setContentOffset(contentoffsetForPage(index), animated: animated);
    }

    func pagingScrollViewFrame() -> CGRect {
        var rect = self.view.bounds;
        rect.size.width += CGFloat(PADDING) * 2;
        rect.origin.x -= CGFloat(PADDING);
        
        return rect;
    }
    
    func pageForPhoto(photo: Photo) ->DisplayView? {
        for page in self.visiblePages {
            if page.photo === photo {
                return page;
            }
        }
        
        return nil;
    }
    
    func displayPageFrame(index: Int) -> CGRect {
        var rect = pagingScrollView.bounds;
        rect.origin.x = (rect.width * CGFloat(index)) + CGFloat(PADDING);
        rect.size.width -= CGFloat(PADDING * 2);
        
        return rect;
    }
    
    func pagingScrollViewContentSize() -> CGSize {
        let width = pagingScrollView.bounds.width;
        return CGSizeMake(width * CGFloat(numOfPhotos()), pagingScrollView.bounds.height);
    }
    
    func contentoffsetForPage(index:Int) -> CGPoint {
        let rect = pagingScrollView.bounds;
        let offset = CGPointMake(rect.size.width * CGFloat(index), 0);
        
        return offset;
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func numOfPhotos() -> NSInteger {
        
        if let del = self.delegate {
            return del.numberOfPhotos();
        } else {
            return 0;
        }
    }
    
    func tilePage() {
        let visibleBounds = pagingScrollView.bounds;
        
        var leftEdgeIndex = Int((floorf(Float(CGRectGetMinX(visibleBounds)) + 2 * PADDING) / Float(CGRectGetWidth(visibleBounds))));
        var rightEdgeIndex = Int((floorf(Float(CGRectGetMaxX(visibleBounds)) - 2 * PADDING - 1) / Float(CGRectGetWidth(visibleBounds))));
        
        if leftEdgeIndex < 0 {
            leftEdgeIndex = 0;
        } else if leftEdgeIndex > (numOfPhotos() - 1) {
            leftEdgeIndex = numOfPhotos() - 1;
        }
        
        if rightEdgeIndex > numOfPhotos() - 1 {
            rightEdgeIndex = numOfPhotos() - 1;
        } else if rightEdgeIndex < 0 {
            rightEdgeIndex = 0;
        }
//        print("leftEdgeIndex = " + String(leftEdgeIndex) + "rightEdgeIndex =" + String(rightEdgeIndex));
        
        var pageIndex:Int;
        // 循环利用
        for page in visiblePages as Set<DisplayView> {
            pageIndex = page.index;
            if (pageIndex < leftEdgeIndex || pageIndex > rightEdgeIndex) {
                recyclePage.insert(page);
                visiblePages.remove(page);
                page.prepareToReuse();
            }
        }
      
        
//        print("recyclePage.count = \(recyclePage.count)");
//        visiblePages
        while recyclePage.count > 2 {
            recyclePage.remove(recyclePage.first!);
        }
        
        // 补上需要显示的页面
        for i in leftEdgeIndex...rightEdgeIndex {
            // 如果计算出来需要展示的页面已经在展示了。就跳过
            if (!isDisplayingPageForIndex(i)) {
                var page: DisplayView;
                if let result = dequeueRecycledPage() {
                    page = result;
                } else {
                    page = DisplayView(browser: self);
                }
                visiblePages.insert(page);
                configurePage(page, index: i);
                pagingScrollView.addSubview(page);
                if page.photo != nil {
                    preloadNearbyImage(page.photo!);
                }
            }

        }
    }
    
    func isDisplayingPageForIndex(index: Int) -> Bool {
        for page in visiblePages {
            if page.index == index {
                return true;
            }
        }
        
        return false;
    }
    
    func dequeueRecycledPage() -> DisplayView? {
        if let page = recyclePage.first {
            recyclePage.remove(page);
            return page;
        } else {
            return nil;
        }
    }
    
    /**
     设置page的frame和index
     */
    func configurePage(page:DisplayView, index:Int) {
        page.index = index;
        page.frame = displayPageFrame(index);
        
        let photo = self.delegate?.photoAtIndex(index);
        if photo != nil {
            // 这句代码要放在设置frame之后。因为其中牵涉到了bounds的计算
            page.setPhoto(photo!);
        }

    }
    
    
    override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
        print("didRotate");
        rotating = false;
    }
    
    override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
        print("willRotate");
        indexBeforeRotate = currentPage;
        rotating = true;
    }
    
    override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
        print("animateRotate");
        // 还原
        currentPage = indexBeforeRotate;
        layoutVisiblePages();
    }
    
    /**
     旋转时重新计算frame。contentsize和offset
     */
    func layoutVisiblePages() {
        pagingScrollView.frame = pagingScrollViewFrame();
        pagingScrollView.contentSize = pagingScrollViewContentSize();
        
        pagingScrollView.contentOffset = contentoffsetForPage(currentPage);
        for page in visiblePages {
            let index = page.index;
            
            
            page.frame = displayPageFrame(index);
            // 这一句很重要。在旋转后调整imageView的缩放大小需要放在设置frame后面
            if !CGRectEqualToRect(previousBounds, view.bounds) {
                page.setMaxMinZoomScaleForCurrentBounds();
                
                // 这一句也非常重要。否则会在计算小图片时iamgeview的frame出错
                page.setNeedsLayout();
                previousBounds = view.bounds;
            }
        }
        
//        print("currentPage = \(currentPage)");
        
    }
    
    func imageForPhoto(photo: Photo?) -> UIImage? {
        if photo != nil {
            if photo!.image != nil {
                return photo!.image!;
            } else {
                photo!.fetchImageAndNotify();
            }
        }
        
        return nil;
    }
    
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent;
    }
    
    func imageDidDownload(noti: NSNotification) {
        dispatch_async(dispatch_get_main_queue()) { 
            let photo = noti.object as! Photo;
            let page = self.pageForPhoto(photo);
            if let pg = page {
                pg.displayImage(photo.image);
                pg.hideProgressView();
//                self.preloadNearbyImage(photo);
            }

        }
    }
    
    /**
     预加载当前显示图片左右两边的图片
     */
    func preloadNearbyImage(photo:Photo) {
        let page = pageForPhoto(photo);
        if page != nil {
            if page!.index == currentPage {
                let former = page!.index - 1;
                let after = page!.index + 1;
                if former >= 0  {
                    let photo = self.delegate?.photoAtIndex(former);
                    if photo?.image == nil {
                        photo?.loadImageAndNotify();
                    }
                }
                
                if after < (numOfPhotos() - 1) {
                    let photo = self.delegate?.photoAtIndex(after);
                    if photo?.image == nil {
                        photo?.loadImageAndNotify();
                    }
                }
            }
        }
    }
    
    deinit {
        print("browser deinit");
        NSNotificationCenter.defaultCenter().removeObserver(self);
        visiblePages.removeAll();
        recyclePage.removeAll();
        KingfisherManager.sharedManager.cache.clearMemoryCache();
    }
}

protocol PhotoBrowserDelegate: NSObjectProtocol {
    func numberOfPhotos() -> Int;
    func photoAtIndex(index:Int) -> Photo;
}

extension PhotoBrowser: UIScrollViewDelegate {
    
    func scrollViewDidScroll(scrollView: UIScrollView) {
        if rotating || !viewIsActive || isPerformLayout {
            return;
        }
        
        tilePage();
        let visibleBounds = pagingScrollView.bounds;
        // 去midx是因为此处是当某个页面超过50%的宽度才算是移动到了该页
//        print("scrollView.contentOffset = \(scrollView.contentOffset))")
        currentPage = Int(floorf(Float(CGRectGetMidX(visibleBounds)) / Float(CGRectGetWidth(visibleBounds))))
//        print("currentPage = \(currentPage)");
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
//        print("recyclePage = \(recyclePage) \n visiblePages = \(visiblePages)");

    }
}

